package com.gome.ocean.controller.gddl.cluster;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.gome.framework.util.DateUtil;
import com.gome.framework.util.StringUtil;
import com.gome.ocean.common.enums.ProxyStatus;
import com.gome.ocean.common.enums.ProxyType;
import com.gome.ocean.common.exception.EntityCreateException;
import com.gome.ocean.common.utils.FormatUtil;
import com.gome.ocean.common.utils.MathUtil;
import com.gome.ocean.common.utils.Pair;
import com.gome.ocean.common.utils.ResponsePage;
import com.gome.ocean.dao.gddl.ProxyAdapterDAO;
import com.gome.ocean.dao.model.authority.ProjectBO;
import com.gome.ocean.dao.model.gddl.*;
import com.gome.ocean.service.authority.ProjectService;
import com.gome.ocean.service.base.AuthorityBaseController;
import com.gome.ocean.service.gddl.ClusterService;
import com.gome.ocean.service.gddl.ProxyService;
import com.google.common.collect.Lists;

/**
 * Created by liuqingxia on 2016/3/28.
 */
@Controller
@RequestMapping("/tddl/cluster")
public class ClusterController extends AuthorityBaseController {

    private static final Logger LOG                 = LoggerFactory.getLogger(ClusterController.class);

    private static final int    NET_IN              = 1;
    private static final int    NET_OUT             = 2;
    private static final int    CONNECTION          = 3;
    private static final int    REQUEST_COUNT       = 4;

    @Autowired
    private ProxyService        proxyService;
    @Autowired
    private ClusterService      clusterService;
    @Autowired
    private ProjectService      projectService;

    private String              createClusterErrMsg = "创建Cluster时发生异常，请检查请求参数后重新提交";

    @RequestMapping(value = "/insert", method = RequestMethod.GET)
    public String toInsertPage(ModelMap m) {
        m.put("currUser", getCurrentUserName());
        List<ProjectBO> projectList = projectService.getAllProjects();
        m.put("projectList", projectList);
        return "gddl/cluster/insert";
    }

    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage insert(@RequestParam("name") String name, @RequestParam("deploycontact") String deploycontact,
                               @RequestParam("project") String projectName) {

        ResponsePage page = getResponsePage();
        ClusterBO clusterBO;
        try {
            clusterBO = createCluster(name, deploycontact, projectName);
        } catch (EntityCreateException e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
        if (null == clusterBO) {
            return page.setErrorMsg(createClusterErrMsg);
        }
        try {
            boolean flag = super.permitAccess(clusterBO);
            if (flag) {
                if (clusterService.insertClusterBO(clusterBO)) {
                    return page.setSuccessMsg("创建集群成功");
                } else {
                    return page.setErrorMsg("创建集群失败");
                }
            }
            return page.setErrorMsg("您没有项目组访问权限");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    private ClusterBO createCluster(String name, String deploycontact, String projectName) throws EntityCreateException {
        if (StringUtil.isBlank(name)) {
            throw new EntityCreateException("集群名称不能为空");
        }
        if (StringUtil.isBlank(deploycontact)) {
            throw new EntityCreateException("集群联系人不能为空");
        }
        ClusterBO clusterBO = new ClusterBO();
        clusterBO.setName(name);
        clusterBO.setDeploycontact(deploycontact);
        clusterBO.setOnlinetime(new Date());
        clusterBO.setProject(projectName);
        return clusterBO;
    }

    @RequestMapping(value = "/remove", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage remove(long clusterId) {
        ResponsePage page = getResponsePage();
        try {
            ClusterBO cluster = clusterService.findClusterBOById(clusterId);
            if (!permitAccess(cluster)) {
                return page.setErrorMsg("您没有权限访问此集群记录");
            }
            if (clusterService.removeClusterBOById(clusterId)) {
                return page.setSuccessMsg("删除集群成功");
            } else {
                return page.setErrorMsg("删除集群失败");
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage update() {
        ResponsePage page = getResponsePage();
        ClusterBO cluster;
        try {
            cluster = createClusterFromReq();
            cluster.setProject(clusterService.findClusterBOById(cluster.getId()).getProject());
        } catch (EntityCreateException e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
        if (null == cluster) {
            return page.setErrorMsg(createClusterErrMsg);
        }
        try {
            if (!permitAccess(cluster)) {
                return page.setErrorMsg("您没有权限访问此集群记录");
            }
            if (clusterService.updateCluster(cluster)) {
                return page.setSuccessMsg("更新集群信息成功");
            } else {
                return page.setErrorMsg("更新集群信息失败");
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    private ClusterBO createClusterFromReq() throws EntityCreateException {
        HttpServletRequest req = getHttpRequest();
        String idStr = req.getParameter("id");
        String name = req.getParameter("name");
        String deploycontact = req.getParameter("deploycontact");
        String onlinetime = req.getParameter("onlinetime");
        long id;
        if (StringUtil.isBlank(idStr)) {
            throw new EntityCreateException("请输入id");
        }
        if (StringUtil.isBlank(name)) {
            throw new EntityCreateException("请输入集群名称");
        }
        if (StringUtil.isBlank(deploycontact)) {
            throw new EntityCreateException("请输入集群联系人");
        }
        if (StringUtil.isBlank(onlinetime)) {
            throw new EntityCreateException("请输入集群上线时间");
        }
        id = Long.parseLong(idStr.trim());
        name = name.trim();
        deploycontact = deploycontact.trim();
        onlinetime = onlinetime.trim();
        ClusterBO clusterBO = new ClusterBO();
        clusterBO.setId(id);
        clusterBO.setName(name);
        clusterBO.setOnlinetime(DateUtil.parse(onlinetime, "yyyy-MM-dd hh:mm:ss"));
        clusterBO.setDeploycontact(deploycontact);
        return clusterBO;
    }

    @RequestMapping(value = "/board", method = RequestMethod.GET)
    public String board(ModelMap m) {
        m.put("clusterResultVOs", getAllClusterResults().getList());
        return "gddl/cluster/board";
    }

    @RequestMapping(value = "/getAllClusterResults", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage<ClusterResultVO> getAllClusterResults() {
        ResponsePage page = getResponsePage();
        List<ClusterResultVO> clusterResultVOs = Lists.newArrayList();
        List<ClusterResultVO> lastClusterResults = getLastClusterResults();
        try {
            List<String> projectNames = getCurrentUserProjects();
            List<Long> ids = clusterService.findAllClusterIdsByProjects(projectNames);
            if (null == ids || ids.isEmpty()) {
                return page.emptyPage("未查询到结果");
            }
            for (Long id : ids) {
                String lastClusterResultJson = getLastClusterResultJson(id, lastClusterResults);
                ClusterResultVO clusterResultVO = getClusterResultVO(id, lastClusterResultJson);
                if (null != clusterResultVO) {
                    clusterResultVOs.add(clusterResultVO);
                }
            }
            return page.setJustList(clusterResultVOs, "查询成功");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    private List<ClusterResultVO> getLastClusterResults() {
        HttpServletRequest req = getHttpRequest();
        String lastClusterResultsStr = req.getParameter("lastClusterResults");
        if (StringUtils.isBlank(lastClusterResultsStr)) {
            return Collections.EMPTY_LIST;
        }
        return JSON.parseArray(lastClusterResultsStr, ClusterResultVO.class);
    }

    private String getLastClusterResultJson(long id, List<ClusterResultVO> clusterResultVOs) {
        for (ClusterResultVO clusterResultVO : clusterResultVOs) {
            if (clusterResultVO.getId() == id) {
                return JSON.toJSONString(clusterResultVO);
            }
        }
        return "";
    }

    private ClusterResultVO getClusterResultVO(long id, String lastClusterResultJson) {
        ResponsePage page = getClusterInfo(id, lastClusterResultJson);
        ClusterResultVO clusterResultVO = (ClusterResultVO) page.getList().get(0);
        return clusterResultVO;
    }

    @RequestMapping(value = "/hardware", method = RequestMethod.GET)
    public String hardware(@RequestParam("clusterId") long clusterId, ModelMap m) {
        String clusterName;
        List<ProxyBO> proxyBOs;
        try {
            ClusterBO clusterBO = clusterService.findClusterBOById(clusterId);
            if (null == clusterBO) {
                m.put("errorMsg", "未查找到相关集群记录");
                return "gddl/cluster/hardware";
            }
            clusterName = clusterBO.getName();
            if (!permitAccess(clusterBO)) {
                m.put("errorMsg", "您没有权限访问此集群记录");
                return "gddl/cluster/hardware";
            }
            proxyBOs = proxyService.getProxyList(clusterId, ProxyStatus.ACTIVE.getValue());
            m.put("clusterName", clusterName);
            m.put("proxyBOs", proxyBOs);

        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            m.put("errorMsg", e.getMessage());
        }

        return "gddl/cluster/hardware";

    }

    @RequestMapping(value = "/find", method = RequestMethod.GET)
    public String toFindPage() {
        return "gddl/cluster/find";
    }

    @RequestMapping(value = "/find", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage find() {
        ResponsePage page = getResponsePage();
        Page<ClusterBO> clusterBOs;
        int pageNum = getPageNum();
        int pageSize = getPageSize();
        try {
            clusterBOs = clusterService.findClusterBOs(pageNum, pageSize);
            if (null == clusterBOs || clusterBOs.isEmpty()) {
                return page.emptyPage(FIND_NO_RESULTS);
            }
            return page.setPage(clusterBOs, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }

    }

    @RequestMapping(value = "/findByName", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findByName(@RequestParam("name") String name) {
        ResponsePage page = getResponsePage();
        List<ClusterBO> clusterBOs;
        int pageNum = getPageNum();
        int pageSize = getPageSize();
        try {
            clusterBOs = clusterService.findClusterBOByName(name, pageNum, pageSize);
            if (null == clusterBOs || clusterBOs.isEmpty()) {
                return page.emptyPage(FIND_NO_RESULTS);
            }
            return page.setJustList(clusterBOs, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/findById", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findById(@RequestParam("id") long id) {
        ResponsePage page = getResponsePage();
        ClusterBO clusterBO = null;
        try {
            clusterBO = clusterService.findClusterBOById(id);
            if (null == clusterBO) {
                return page.emptyPage(FIND_NO_RESULTS);
            }
            return page.setSingleObject(clusterBO, FIND_SUCCESS);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    /**
     * 获取单个集群内存使用率
     * 
     * @param clusterId
     * @return
     */
    @RequestMapping("/proxyMemoryUsage")
    @ResponseBody
    public ResponsePage proxyMemoryUsage(@RequestParam("clusterId") long clusterId) {
        ResponsePage page = getResponsePage();
        List<Pair<Long, Integer>> result = new ArrayList<Pair<Long, Integer>>();
        List<ProxyBO> proxys = proxyService.getProxyList(clusterId, ProxyStatus.ACTIVE.getValue());
        for (ProxyBO node : proxys) {
            ProxyAdapterDAO perfAccesser = proxyService.getAccesser(node.getId(), ProxyType.MANAGER);
            if (perfAccesser == null) {
                return page.setErrorMsg("找不到proxy node!");
            }
            if (!perfAccesser.checkConnection()) {
                StringBuilder sb = new StringBuilder("listCobarMemoryUsage: cobar connect error for Name:");
                sb.append(node.getName()).append(" Host:").append(node.getHost());
                LOG.error(sb.toString());
                continue;
            }
            ServerStatusVO ss = perfAccesser.getServerStatus();
            int memoryUsage = 0;
            if (ss.getTotalMemory() != 0) memoryUsage = Math.round(ss.getUsedMemory() * 100 / ss.getTotalMemory());
            result.add(new Pair<Long, Integer>(node.getId(), memoryUsage));
        }
        return page.setJustList(result, "内存使用率查询成功!");
    }

    /**
     * 获取单个集群的统计信息 包括流量输入输出 等.
     * 
     * @param clusterId
     * @return
     */
    @RequestMapping("/getClusterInfo")
    @ResponseBody
    private ResponsePage getClusterInfo(@RequestParam("clusterId") long clusterId,
                                        @RequestParam("lastClusterInfo") String lastClusterInfo) {
        ResponsePage page = getResponsePage();

        JSONObject jsonObject = null;
        if (StringUtils.isNotEmpty(lastClusterInfo)) {
            jsonObject = JSONObject.parseObject(lastClusterInfo);
        }

        ClusterResultVO cluster = new ClusterResultVO();
        cluster.setId(clusterId);
        ClusterBO clusterBO = clusterService.findClusterBOById(clusterId);
        cluster.setName(clusterBO.getName());
        cluster.setDeploycontact(clusterBO.getDeploycontact());
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        cluster.setOnlinetime(format.format(clusterBO.getOnlinetime()));

        List<ProxyBO> nodes = proxyService.getProxyList(clusterId, ProxyStatus.ACTIVE.getValue());
        cluster.setTotal(nodes.size());

        long timestamp = 0;
        for (ProxyBO proxy : nodes) {
            if (ProxyStatus.INACTIVE.getValue() == proxy.getStatus()) {
                continue;
            }
            ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxy.getId(), ProxyType.MANAGER);
            if (perfAccesser == null) {
                cluster.addError(1);
                StringBuilder sb = new StringBuilder("getClusterInfo : proxy connect error for [ Name:");
                sb.append(proxy.getName()).append(" Host:").append(proxy.getHost()).append(" ]");
                LOG.error(sb.toString());
                continue;
            }
            if (!perfAccesser.checkConnection()) {
                cluster.addError(1);
                try {
                    perfAccesser.destroy();
                } catch (Exception e) {
                }
                proxy.setStatus(ProxyStatus.ERROR.getValue());
                try {
                    proxyService.updateProxyBO(proxy);
                } catch (Exception e) {
                    return page.setErrorMsg(e.getMessage());
                }
                StringBuilder sb = new StringBuilder("getClusterInfo : proxy connect error for [ Name:");
                sb.append(proxy.getName()).append(" Host:").append(proxy.getHost()).append(" ]");
                LOG.error(sb.toString());
                continue;
            }
            cluster.addActive(1);
            cluster.setSchema(perfAccesser.listDataBases().size());
            List<ProcessorStatusVO> list = perfAccesser.listProccessorStatus();
            cluster.addNetIn(groupByPList(list, NET_IN));
            cluster.addNetOut(groupByPList(list, NET_OUT));

            cluster.addConnection(groupByPList(list, CONNECTION));
            timestamp = list.get(list.size() - 1).getSampleTimeStamp();
            cluster.setTimestamp(timestamp);

            List<CommandStatusVO> commandList = perfAccesser.listCommandStatus();
            cluster.addRequest(groupByCList(commandList, REQUEST_COUNT));
        }

        if (null != jsonObject && jsonObject.getLong("netIn") != -1) {
            long o_tiemstamp = jsonObject.getLong("timestamp");
            cluster.setNetIn_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cluster.getNetIn(),
                jsonObject.getLong("netIn"),
                timestamp,
                o_tiemstamp,
                1000.0))));
            cluster.setNetOut_deriv(FormatUtil.formatNetwork(Math.round(MathUtil.getDerivate(cluster.getNetOut(),
                jsonObject.getLong("netOut"),
                timestamp,
                o_tiemstamp,
                1000.0))));
            cluster.setRequest_deriv(FormatUtil.formatNumber(Math.round(MathUtil.getDerivate(cluster.getRequest(),
                jsonObject.getLong("request"),
                timestamp,
                o_tiemstamp,
                1000.0))));
        }
        return page.setSingleObject(cluster, "集群查询成功!");
    }

    private long groupByPList(List<ProcessorStatusVO> list, int type) {
        long result = 0;
        switch (type) {
            case NET_IN:
                for (ProcessorStatusVO p : list) {
                    result += p.getNetIn();
                }
                break;
            case NET_OUT:
                for (ProcessorStatusVO p : list) {
                    result += p.getNetOut();
                }
                break;
            case CONNECTION:
                for (ProcessorStatusVO p : list) {
                    result += p.getConnections();
                }
                break;
            case REQUEST_COUNT:
                for (ProcessorStatusVO p : list) {
                    result += p.getRequestCount();
                }
                break;
            default:
                throw new IllegalArgumentException("invalid parameter");
        }
        return result;
    }

    private long groupByCList(List<CommandStatusVO> list, int type) {
        long result = 0;
        switch (type) {
            case REQUEST_COUNT:
                for (CommandStatusVO p : list) {
                    result += p.getQuery();
                }
                break;
            default:
                throw new IllegalArgumentException("invalid parameter");
        }
        return result;
    }
}
